In [1]:
import dicom
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode()
In [2]:
dcm_plan = dicom.read_file("RP1.3.6.1.4.1.2452.6.728760501.1211531093.3851412398.2396712583.dcm", force=True)
In [3]:
def pull_dwells(dcm):
    dwell_channels = []
    all_dwell_positions = []
    
    number_of_channels = len(dcm.ApplicationSetupSequence[0].ChannelSequence)

    for i in range(number_of_channels):
        BrachyControlPointSequence = (
            dcm.ApplicationSetupSequence[0].ChannelSequence[i].BrachyControlPointSequence)
        number_of_dwells_in_channel = len(BrachyControlPointSequence)

        channel_dwells_positions = []
        for j in range(number_of_dwells_in_channel):
            if len(BrachyControlPointSequence[j].dir("ControlPoint3DPosition")) != 0:
                channel_dwells_positions.append(
                    BrachyControlPointSequence[j].ControlPoint3DPosition)
                dwell_channels.append(i+1)

        all_dwell_positions += channel_dwells_positions

    dwell_channels = np.array(dwell_channels)
    dwell_positions = np.array(all_dwell_positions).astype(float)
    
    return dwell_positions, dwell_channels

dwell_positions, dwell_channels = pull_dwells(dcm_plan)
In [4]:
dcm_plan.SourceSequence[0]
Out[4]:
(300a, 0212) Source Number                       IS: '0'
(300a, 0214) Source Type                         CS: 'LINE'
(300a, 0226) Source Isotope Name                 LO: 'Ir-192'
(300a, 0228) Source Isotope Half Life            DS: '73.8300000000000'
(300a, 0229) Source Strength Units               CS: 'AIR_KERMA_RATE'
(300a, 022a) Reference Air Kerma Rate            DS: '43939.3000000000'
(300a, 022c) Source Strength Reference Date      DA: '20151201'
(300a, 022e) Source Strength Reference Time      TM: '000000'
(300b, 0010) Private Creator                     LO: 'NUCLETRON'
(300b, 1006) Private tag data                    DS: '-100557'
(300b, 1007) Private tag data                    DS: '-100631'
(300b, 1008) Private tag data                    DT: '20151130140000'
(300b, 100c) Private tag data                    DS: ''
In [5]:
dcm_plan[0x300f,0x1000][0].dir()
Out[5]:
['ROIContourSequence',
 'RTROIObservationsSequence',
 'RefdFrameOfReferenceSequence',
 'ReferencedFrameOfReferenceSequence',
 'StructureSetDate',
 'StructureSetLabel',
 'StructureSetName',
 'StructureSetROISequence',
 'StructureSetTime']
In [6]:
dcm_plan[0x300f,0x1000][0].ROIContourSequence[0]
Out[6]:
(0021, 0010) Private Creator                     LO: 'NUCLETRON'
(0021, 1000) Private tag data                    UI: 1.2.840.113619.2.278.3.380434001.422.1404078961.990
(3006, 002a) ROI Display Color                   IS: ['255', '0', '0']
(3006, 0040)  Contour Sequence   1 item(s) ---- 
   (3006, 0042) Contour Geometric Type              CS: 'OPEN_NONPLANAR'
   (3006, 0046) Number of Contour Points            IS: '93'
   (3006, 0048) Contour Number                      IS: '1'
   (3006, 0050) Contour Data                        DS: ['-33.540318', '14.369348', '-134.750000', '-33.837937', '13.915945', '-132.250000', '-34.040225', '13.671804', '-129.750000', '-34.113150', '13.649609', '-127.250000', '-34.261114', '13.481917', '-124.750000', '-34.423874', '13.427664', '-122.250000', '-34.423874', '13.427664', '-119.750000', '-34.645820', '13.250107', '-117.250000', '-34.814499', '13.183523', '-114.750000', '-34.857902', '13.102143', '-112.250000', '-34.966409', '13.102143', '-109.750000', '-35.156296', '13.037039', '-107.250000', '-35.237676', '12.993636', '-104.750000', '-35.346183', '12.613862', '-102.250000', '-35.400436', '12.451102', '-99.750000', '-35.461472', '12.023856', '-97.250000', '-35.644577', '11.718680', '-94.750000', '-35.725957', '11.420286', '-92.250000', '-35.834464', '11.311779', '-89.750000', '-35.888718', '11.474540', '-87.250000', '-35.834464', '11.637300', '-84.750000', '-35.888717', '11.718680', '-82.250000', '-35.888718', '11.962821', '-79.750000', '-35.888717', '12.060477', '-77.250000', '-35.888718', '11.962821', '-74.750000', '-35.986374', '11.718680', '-72.250000', '-35.949753', '11.535575', '-69.750000', '-36.028226', '11.474540', '-67.250000', '-35.949753', '11.413504', '-64.750000', '-35.942971', '11.311779', '-62.250000', '-35.942971', '11.149019', '-59.750000', '-35.949753', '11.047294', '-57.250000', '-35.949753', '11.047294', '-54.750000', '-36.028226', '10.986259', '-52.250000', '-36.028226', '10.986259', '-49.750000', '-36.028226', '10.986259', '-47.250000', '-36.028226', '10.986259', '-44.750000', '-36.028226', '10.986259', '-42.250000', '-36.028226', '10.986259', '-39.750000', '-36.028226', '10.986259', '-37.250000', '-36.028226', '10.986259', '-34.750000', '-36.028226', '10.986259', '-32.250000', '-36.028226', '10.986259', '-29.750000', '-36.028226', '10.986259', '-27.250000', '-36.028226', '10.986259', '-24.750000', '-36.028226', '10.986259', '-22.250000', '-36.028226', '10.986259', '-19.750000', '-36.028226', '10.986259', '-17.250000', '-36.028226', '10.986259', '-14.750000', '-36.028226', '10.986259', '-12.250000', '-36.028226', '10.986259', '-9.750000', '-36.028226', '10.986259', '-7.250000', '-36.028226', '10.986259', '-4.750000', '-36.028226', '10.986259', '-2.250000', '-36.028226', '10.986259', '0.250000', '-36.028226', '10.986259', '2.750000', '-36.028226', '10.986259', '5.250000', '-36.028226', '10.986259', '7.750000', '-36.028226', '10.986259', '10.250000', '-36.028226', '10.986259', '12.750000', '-36.132858', '11.230399', '15.250000', '-35.986374', '11.230399', '17.750000', '-35.986374', '11.230399', '20.250000', '-36.279342', '11.230399', '22.750000', '-36.132858', '11.279227', '25.250000', '-36.132858', '11.230399', '27.750000', '-36.132858', '11.230399', '30.250000', '-36.322745', '11.311779', '32.750000', '-36.214238', '11.257526', '35.250000', '-36.237490', '11.474540', '37.750000', '-36.254928', '11.352469', '40.250000', '-36.237490', '11.474540', '42.750000', '-36.237490', '11.474540', '45.250000', '-36.237490', '11.474540', '47.750000', '-36.315963', '11.413504', '50.250000', '-36.237490', '11.474540', '52.750000', '-36.237490', '11.474540', '55.250000', '-36.237490', '11.474540', '57.750000', '-36.237490', '11.474540', '60.250000', '-36.237490', '11.474540', '62.750000', '-36.132858', '11.474540', '65.250000', '-36.132858', '11.474540', '67.750000', '-36.237490', '11.474540', '70.250000', '-36.132858', '11.474540', '72.750000', '-36.132858', '11.474540', '75.250000', '-36.132858', '11.474540', '77.750000', '-36.132858', '11.474540', '80.250000', '-36.028226', '11.474540', '82.750000', '-36.028226', '11.474540', '85.250000', '-36.028226', '11.474540', '87.750000', '-36.028226', '11.474540', '90.250000', '-36.028226', '11.474540', '92.750000', '-36.689603', '10.458016', '105.250000']
   ---------
(3006, 0084) Referenced ROI Number               IS: '0'
In [7]:
def pull_plan_structure(dcm, index):   
    contours_by_slice_raw = [
        item.ContourData for item in dcm[0x300f,0x1000][0].ROIContourSequence[index].ContourSequence]
    x = [np.array(item[0::3]) for item in contours_by_slice_raw]
    y = [np.array(item[1::3]) for item in contours_by_slice_raw]
    z = [np.array(item[2::3]) for item in contours_by_slice_raw]
    return x, y, z

x, y, z = pull_plan_structure(dcm_plan, 0)
In [8]:
def display_plan_structures(dcm, list_of_indices, dwells, colour_list=None):    
    combined_trace = []
    
    for i, index in enumerate(list_of_indices):
        if colour_list is None:
            colour = 'black'
        else:
            colour = colour_list[i]

        x, y, z = pull_plan_structure(dcm, index)
        
        for i in range(len(x)):
            trace = go.Scatter3d(
                x=x[i], 
                y=y[i], 
                z=z[i],  
                mode='lines', line=go.Line(color=colour, width=3))

            combined_trace.append(trace)
            
    trace = go.Scatter3d(
        x=dwells[:,0], 
        y=dwells[:,1], 
        z=dwells[:,2], mode='markers')
    combined_trace.append(trace)
    
    iplot(go.Figure(
            data=go.Data(combined_trace),
            layout=go.Layout(
                showlegend=False,
                width=900, height=800
            )
        ))

Final diagram

In [9]:
display_plan_structures(dcm_plan, np.arange(21), dwell_positions)
In [ ]: